import java.net.*;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;

public class FIFOReliableChannel extends BroadcastChannel implements ApplicationListener {
    ReliableChannel rc;
    ApplicationListener listener;
    HashMap<ChatClientRecord, Long> nextMap;
    ArrayList<ChatMessage> msgBag;

    public FIFOReliableChannel(ChatClientRecord rec, ApplicationListener l){
        listener = l;
        nextMap = new HashMap<ChatClientRecord, Long>();
        msgBag = new ArrayList<ChatMessage>();
        rc = new ReliableChannel(rec, this);
    }

    public boolean addMember(ChatClientRecord member){
        return rc.addMember(member);
    }

    public boolean removeMember(ChatClientRecord member){
        return rc.removeMember(member);
    }

    public ArrayList<ChatClientRecord> getMembers(){
        return rc.getMembers();
    }

    public boolean sendMessage(ChatMessage m){
        return rc.sendMessage(m);
    }

    public void receive(ChatMessage m){
        ChatClientRecord p = m.clientRec; // p := sender(m)
        msgBag.add(m); // msgBag := msgBag U {m}
        boolean foundMatch = true;
        while(foundMatch){//while there exists an mPrime in msgBag such that sender(mPrime) == p && messID(mPrime) == next[p]
            foundMatch = false;
            for(int i = 0; i < msgBag.size(); i++){//loop over the message bag
                ChatMessage mPrime = msgBag.get(i);//mPrime is the entry in the message bag
                if(p.equals(mPrime.clientRec)){//if mPrime came from the same client as 'm'
                    Long nextIDtmp = nextMap.get(p);//get the next ID we need to deliver
                    if(nextIDtmp != null){//if we have a 'next ID'
                        long nextID = nextIDtmp.longValue();
                        if(nextID == mPrime.messID){//if the 'next ID' is the same as mPrime's ID then deliver it
                            foundMatch = true;
                            nextMap.put(p, new Long(mPrime.messID+1));//next[p]++
                            listener.receive(mPrime);//deliver(mPrime)
                            msgBag.remove(i);//msgBag := msgBag \ {mPrime}
                        }
                    }else{//if we don't have a 'next ID' then this is the first message from this broadcaster we've received
                        foundMatch = true;
                        nextMap.put(p, new Long(mPrime.messID+1));//next[p]++
                        listener.receive(mPrime);//deliver(mPrime)
                        msgBag.remove(i);//msgBag := msgBag \ {mPrime}
                    }
                }
            }
        }
    }
}
